#include "sparse_matrix.h"

sparse_matrix_lst* allocate_sparse_matrix_lst(int n)
{
	sparse_matrix_lst *rVal = (sparse_matrix_lst *)malloc(sizeof(sparse_matrix_lst));
	rVal->cols = (cell_t **)calloc(sizeof(cell_t *),n);
	rVal->rows = (cell_t **)calloc(sizeof(cell_t *),n);
	rVal->n = n;
	return rVal;
}

void free_sparse_matrix_lst(sparse_matrix_lst* matrix)
{
	int i;
	for (i=0; i<matrix->n;i++)
	{
		delete_list(matrix->rows[i]);
	}
	free (matrix->cols);
	free (matrix->rows);
	free (matrix);
}


/* recursive deletion of a list */
void delete_list(cell_t *head)
{
	if (head != NULL) 
	{
		delete_list(head->row_next);
		free(head);
	}
}

void mult_sparse_list(const sparse_matrix_lst *A, const elem *v, elem** result)
{
	int n = A->n;
	int i;
	cell_t *head;
	for (i=0;i<n;i++)
	{
		head = A->rows[i];
		while (head!=NULL)
		{
			(*result)[i] += (head->value * v[head->colind]);
			head = head->row_next;
		}
	}
}

void mult_sparse_list_with_int_vector(const sparse_matrix_lst *A, const int *v, elem** result)
{
	int n = A->n;
	int i;
	cell_t *head;
	for (i=0;i<n;i++)
	{
		head = A->rows[i];
		while (head!=NULL)
		{
			(*result)[i] += (head->value * v[head->colind]);
			head = head->row_next;
		}
	}
}


elem calcSparseMatrix1Norm(sparse_matrix_lst *A)
{
	int n = A->n;
	int j, maxJ;
	elem colResult = 0, maxResult = 0, dTemp;
	cell_t *head;
	for (j=0;j<n;j++)
	{
		head = A->cols[j];
		while (head != NULL)
		{
			dTemp = head->value;
			colResult += dTemp>=0?dTemp:-dTemp;/*abs value*/
			head = head->row_next;
		}
		if (colResult > maxResult)
		{
			maxResult = colResult;
			maxJ = j;
		}
	}
	return maxJ;
}

int createSparseMatrixFromFile(char *sFilePath, sparse_matrix_lst **pMatrix, int *pMatrixSize)
{
	int n,i,j;
	elem iTemp;
	cell_t **RowsTails, **ColsTails;
	cell_t *TempCell;
	FILE *fp;
	if (sFilePath == NULL)/*For the main.c*/
		fp = stdin;
	else
	{
		fp = fopen(sFilePath,"r");
		if (fp == NULL)
			return 0;
	}

	/*Get matrix size*/
	if (fscanf(fp, "%d",&n) == 0)
	{
		if (sFilePath != NULL)/*We don't want to close the stdin...*/
		{
			fclose(fp);
		}
		return 0;
	}

	*pMatrixSize = n;/*The size result value*/

	RowsTails = (cell_t **)(calloc(sizeof(cell_t *),n));
	ColsTails = (cell_t **)(calloc(sizeof(cell_t *),n));

	*pMatrix = allocate_sparse_matrix_lst(n);

	for (i=0;i<n;i++)
	{
		for (j=0;j<n;j++)
		{
			if (fscanf(fp,"%lf",&iTemp) == 0)
			{
				if (sFilePath != NULL)/*We don't want to close the stdin...*/
				{
					fclose(fp);
				}
				free_sparse_matrix_lst(*pMatrix);
				printf("ERROR");
				return 0;
			}
			if (iTemp!=0)
			{
				TempCell = (cell_t*)malloc(sizeof(cell_t));
				TempCell->value = iTemp;
				TempCell->colind = j;
				TempCell->rowind = i;
				TempCell->col_next = NULL;
				TempCell->row_next = NULL;
				if (RowsTails[i]!=NULL)
					RowsTails[i]->row_next = TempCell;
				else
					(*pMatrix)->rows[i] = TempCell;
				if (ColsTails[j]!=NULL)
					ColsTails[j]->col_next = TempCell;
				else 
					(*pMatrix)->cols[j] = TempCell;
				RowsTails[i] = TempCell;
				ColsTails[j] = TempCell;
			}
		}
	}
	
	if (sFilePath != NULL)/*We don't want to close the stdin...*/
	{
		fclose(fp);
	}
	free(RowsTails);
	free(ColsTails);
	return 1;
}

int printSparseMatrixByRows(sparse_matrix_lst *A)
{
	cell_t *head;
	int i, j;
	printf("\n");
	for (i=0; i<A->n; i++)
	{
		head = A->rows[i];
		for (j=0; j<A->n; j++)
		{
			if (head == NULL)
			{
				printf("0.0  ");
			}
			else
			{
				if (head->rowind == i && head->colind == j)
				{
					printf("%3.1f  ", head->value);
					head = head->row_next;
				}
				else
				{
					printf("0.0  ");
				}
			}
		}
		printf("\n");
	}
	return 1;
}

int printSparseMatrixByCols(sparse_matrix_lst *A)
{
	cell_t *head;
	int i, j;
	printf("\n");
	for (i=0; i<A->n; i++)
	{
		head = A->cols[i];
		for (j=0; j<A->n; j++)
		{
			if (head == NULL)
			{
				printf("0.0  ");
			}
			else
			{
				if (head->colind == i && head->rowind == j)
				{
					printf("%3.1f  ", head->value);
					head = head->col_next;
				}
				else
				{
					printf("0.0  ");
				}
			}
		}
		printf("\n");
	}
	return 1;
}

int printNormalMatrix(elem **A, int iMatrixSize)
{
	int i,j;
	printf("\n");
	for (i=0; i<iMatrixSize; i++)
		for (j=0; j<iMatrixSize; j++)
			printf("%5.3f  ", A[i][j]);
	return 1;
}

int printVector(elem *V, int iVectorSize)
{
	int i;
	printf("\n");
	for (i=0; i<iVectorSize; i++)
		printf("%5.3f  ", V[i]);
	return 1;
}

int printIntVector(int *V, int iVectorSize, char *path, double grade, int numOfIter)
{
	int i;
	FILE *fp = fopen(path, "a");
	if (fp == NULL)
	{
		printf("ERROR opening output file\n");
		return 0;
	}
	fprintf(fp,"***%d  ", numOfIter);
	fprintf(fp,"###%f  ", grade);
	for (i=0; i<iVectorSize; i++)
		fprintf(fp,"%d  ", V[i]);
	fprintf(fp,"\n");

	fclose(fp);
	return 1;
}

